<template>
  <div class="roles-selector">
    <el-dialog
      :title="dialogTitle"
      :visible.sync="roleVisible"
      :before-close="_handleCancelClick"
      width="574px"
    >
      <div class="flex-column h-100P">
        <el-input v-model="keyword" placeholder="输入关键字搜索" @input="keySearch" />
        <div class="flex-sub" style="overflow: auto;" @scroll="_handleScroll">
          <div ref="rolesTree">
            <el-tree
              ref="tree"
              v-loading="isLoading"
              :data="roleList"
              :props="props"
              :show-checkbox="isMultiSelect"
              default-expand-all
              :node-key="props.nodeKey"
              :expand-on-click-node="false"
              @check="_handleCheck"
              @node-click="_handleCheck"
            />
            <!--            <div v-show="isLoading && total > 0" class="loading pd-left-22">-->
            <!--              <i class="el-icon-loading mg-right-6" />加载中...-->
            <!--            </div>-->
          </div>
        </div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button size="small" type="primary" @click="_handleSubClick">确定</el-button>
        <el-button size="small" @click="_handleCancelClick">取消</el-button>
      </div>
    </el-dialog>
  </div>
</template>
<script>
  /**
   * 角色选择组件
   */
  import { apiGetRoleList } from './api'
  import { MAX_INTEGER } from '../../consts'

  export default {
    name: 'RolesSelector',
    props: {
      lazy: { type: Boolean, default: false },
      roleVisible: { type: Boolean, default: false },
      height: { type: Number, default: 100 },
      dialogTitle: { type: String, default: '选择角色' },
      roles: { type: Array, require: false, default: null },
      pageSize: { type: [Number, String], require: false, default: 10 }, // lazy 为true时有效
      // true 多选, false 单选
      isMultiSelect: { type: Boolean, require: false, default: false },
      props: {
        type: Object,
        require: false,
        default: () => {
          return {
            children: 'children', //
            label: 'name', // 显示文案字段名称
            nodeKey: 'id' // 角色唯一id
          }
        }
      }
    },
    data() {
      return {
        keyword: '',
        isLoading: false,
        pageNo: 1,
        total: -1,
        roleList: [],
        checkedRoleList: []
      }
    },
    computed: {
      hasNext() {
        if (this.total === -1) {
          return true
        } else {
          return this.total >= this.pageNo * this.pageSize
        }
      }
    },
    watch: {
      // keyword(newValue) {
      //   this.$refs.tree.filter(newValue)
      // }
    },
    created() {
      this.initData()
    },
    methods: {
      // 关键字检索
      async keySearch() {
        this.roleList = await this._getRoleList(1, this.pageSize, this.keyword)
      },
      // 初始化组件数据
      initData() {
        // 初始化角色信息列表
        this._initRoleList()
      },
      async _initRoleList() {
        if (this.roles) {
          this.roleList = Object.assign(this.roles)
        } else {
          this.roleList = await this._getRoleList(this.pageNo, this.pageSize)
        }
      },
      /**
       * 根据参数查询角色列表
       * @param pageNo 页码
       * @param pageSize 页大小
       * @param keyword 关键词
       * @return {Array} 角色列表
       */
      async _getRoleList(pageNo, pageSize, keyword) {
        this.isLoading = true
        let ps = pageSize
        if (!this.lazy) {
          ps = MAX_INTEGER
        }
        const { records, pageNo: pageNumber, total } = await apiGetRoleList({
          pageNo: pageNo,
          pageSize: ps,
          keyword
        })
        this.pageNo = pageNumber
        this.total = total
        this.isLoading = false
        return [...records]
      },
      /**
       * 追加角色
       */
      async addRoles() {
        if (!this.hasNext || !this.lazy) {
          return
        }
        const roles = await this._getRoleList(this.pageNo + 1, this.pageSize)
        roles.forEach(role => {
          this.roleList.push(role)
        })
      },
      /**
       * 通过nodeKeyList主动勾选
       * @public
       * @param nodeKeyList 需要勾选的树节点的唯一nodeKey 需要通过参数`props.nodeKey`指定nodeKey的字段
       * @example this.ref.el.setCheckedByNodeKeys([]) // 清空所有选中的角色
       *          this.ref.el.setCheckedByNodeKeys(['123']) // 选中nodeKey值为123的角色
       */
      setCheckedByNodeKeys(nodeKeyList) {
        this.$refs.tree.setCheckedKeys(nodeKeyList)
      },
      _handleScroll(e) {
        if (
          e.target.scrollTop / (this.$refs.rolesTree.offsetHeight - 462) ===
          1
        ) {
          this.addRoles()
        }
      },
      _handleCheck(data) {
        if (this.isMultiSelect) {
          this._checkboxMethod()
        } else {
          this._radioMethod(data)
        }
      },
      // 点击提交按钮
      _handleSubClick() {
        this.$emit('confirmClick', this.checkedRoleList)
      },
      // 点击取消按钮
      _handleCancelClick() {
        this.$emit('cancelClick', false)
      },
      _radioMethod(data) {
        if (
          this.checkedRoleList.findIndex(
            role => role[this.props.nodeKey] === data[this.props.nodeKey]
          ) >= 0
        ) {
          this.checkedRoleList = []
        } else {
          this.checkedRoleList = [data]
        }
        this.setCheckedByNodeKeys(
          this.checkedRoleList.map(role => role[this.props.nodeKey])
        )
        this.$emit('check', this.checkedRoleList)
      },
      _checkboxMethod() {
        this.checkedRoleList = this.$refs.tree.getCheckedNodes()
        this.$emit('check', this.checkedRoleList)
      },
      _filterMethod(value, data) {
        if (!value) {
          return true
        }
        return data[this.props.label].indexOf(value) > -1
      }
    }
  }
</script>

<style lang="scss" scoped>
  .roles-selector {
    .loading {
      color: #606266;
    }

    ::v-deep .el-dialog {
      display: flex;
      height: 668px;
      flex-direction: column;

      .el-dialog__body {
        overflow: auto;
        flex: 1;
      }
    }
  }

  .open-button {
    height: 30px;
    padding: 0 10px;
    font-size: 14px;
    color: #0084ee;
    cursor: pointer;
    border: 1px solid #0084ee;
    border-radius: 4px;
  }
</style>
